//
// Created by HP on 2024/1/1.
//

#include "eflash_driver.h"
#include "rtthread.h"

Eflash_Driver::Eflash_Driver(){
    EFLASH_CS_H;
    hspi = &hspi3;
    _set_spi_mode();
}
void Eflash_Driver::_set_spi_mode(){
//    if(hspi->Init.CLKPhase == SPI_PHASE_1EDGE){
//        return;
//    };

    if (HAL_SPI_DeInit(hspi) != HAL_OK)
    {
        while( true )
            usb_printf("eflash spi deinit error\r\n");
    }

    hspi->Instance = hspi->Instance;
    hspi->Init.Mode = SPI_MODE_MASTER;
    hspi->Init.Direction = SPI_DIRECTION_2LINES;
    hspi->Init.DataSize = SPI_DATASIZE_8BIT;
    hspi->Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi->Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi->Init.NSS = SPI_NSS_SOFT;
    hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi->Init.TIMode = SPI_TIMODE_DISABLE;
    hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi->Init.CRCPolynomial = 10;
    if (HAL_SPI_Init(hspi) != HAL_OK)
    {
        while( true )
            usb_printf("eflash spi deinit error\r\n");
    }
}

/*读取flash的ID 0x4017*/
uint16_t Eflash_Driver::read_jedec_id(){
    _set_spi_mode();

    uint8_t rbuff[3];
    _eflash_read_info(0x9F,rbuff,3);
    return  (rbuff[1] << 8) +  rbuff[2];
}



uint32_t Eflash_Driver::get_block_size(){
    return BLOCK_SIZE;
}
uint32_t Eflash_Driver::get_sector_size(){
    return SECTOR_SIZE;
}

void Eflash_Driver::_eflash_read_info(uint8_t inst,uint8_t *rbuff,uint16_t len){
    _set_spi_mode();

    EFLASH_CS_L;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    HAL_SPI_Receive(hspi,rbuff,len,0xffff);
    EFLASH_CS_H;
}

void Eflash_Driver::_elfash_busy_wait(){
    _set_spi_mode();

    uint8_t inst = 0x05;
    uint8_t rbuff;
    EFLASH_CS_L;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    while(1) {
        HAL_SPI_Receive(hspi, &rbuff, 1, 0xffff);
        if ((rbuff & 0x01) == 0x0)
            break;
    }
    EFLASH_CS_H;
}


void Eflash_Driver::read_data(uint32_t addr,uint8_t *rbuff,uint32_t len){

    rt_interrupt_enter();

    _set_spi_mode();
    uint8_t inst = 0x03;
    _elfash_busy_wait();
    EFLASH_CS_L;
    uint8_t addrbuf[3];
    addrbuf[0] = (addr >> 16) & 0x00ff;
    addrbuf[1] = (addr >> 8)  & 0x0000ff;
    addrbuf[2] = (addr) & 0x000000ff;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[0],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[1],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[2],1,0xffff);
    HAL_SPI_Receive(hspi,rbuff,len,0xffffff);
    EFLASH_CS_H;

    rt_interrupt_leave();
}

void Eflash_Driver::_elfash_wenable(){
    _set_spi_mode();

    uint8_t inst = 0x06;
    EFLASH_CS_L;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    EFLASH_CS_H;
}

/*整片擦除*/
void Eflash_Driver::chip_erase(){
    _set_spi_mode();

    uint8_t inst = 0xC7;
    _elfash_busy_wait();
    _elfash_wenable();
    EFLASH_CS_L;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    EFLASH_CS_H;
}

void  Eflash_Driver::sector_erase(uint32_t addr){
    _set_spi_mode();

    //addr = addr << 12;
    uint8_t inst = 0x20;
    _elfash_busy_wait();
    _elfash_wenable();
    EFLASH_CS_L;
    uint8_t addrbuf[3];
    addrbuf[0] = (addr >> 16) & 0x00ff;
    addrbuf[1] = (addr >> 8)  & 0x0000ff;
    addrbuf[2] = (addr) & 0x000000ff;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[0],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[1],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[2],1,0xffff);
    EFLASH_CS_H;
}

void Eflash_Driver::block_erase(uint32_t addr){
    _set_spi_mode();

    //addr = addr << 16;
    uint8_t inst = 0xD8;
    _elfash_busy_wait();
    _elfash_wenable();
    EFLASH_CS_L;
    uint8_t addrbuf[3];
    addrbuf[0] = (addr >> 16) & 0x00ff;
    addrbuf[1] = (addr >> 8)  & 0x0000ff;
    addrbuf[2] = (addr) & 0x000000ff;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[0],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[1],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[2],1,0xffff);
    EFLASH_CS_H;
}

void Eflash_Driver::write_data(uint32_t addr,uint8_t *wbuff,uint32_t len){
    _set_spi_mode();

    uint8_t inst = 0x02;
    uint16_t start_page_offset;  //开始PAGE偏移地址
    uint16_t end_page_offset;  //开始PAGE偏移地址
    uint32_t start_len;

    start_page_offset = addr & 0x000000FF;

    start_len = (start_page_offset + len > 256 ) ? (256 - start_page_offset) : len;
    usb_printf("%d offset : %d start_len %d\r\n",addr,start_page_offset,start_len);
    _elfash_busy_wait();
    _elfash_wenable();
    uint8_t addrbuf[3];
    addrbuf[0] = (addr >> 16) & 0x00ff;
    addrbuf[1] = (addr >> 8)  & 0x0000ff;
    addrbuf[2] = (addr) & 0x000000ff;
    EFLASH_CS_L;
    HAL_SPI_Transmit(hspi,&inst,1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[0],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[1],1,0xffff);
    HAL_SPI_Transmit(hspi,&addrbuf[2],1,0xffff);
    HAL_SPI_Transmit(hspi,wbuff,start_len,0xffff);
    EFLASH_CS_H;


    if( start_page_offset +  len > 256){
        addr  += start_len;
        wbuff += start_len;
        len   -= start_len;
        while(len >= 256){
            _elfash_busy_wait();
            _elfash_wenable();
            addrbuf[0] = (addr >> 16) & 0x00ff;
            addrbuf[1] = (addr >> 8)  & 0x0000ff;
            addrbuf[2] = (addr) & 0x000000ff;
            EFLASH_CS_L;
            HAL_SPI_Transmit(hspi,&inst,1,0xffff);
            HAL_SPI_Transmit(hspi,&addrbuf[0],1,0xffff);
            HAL_SPI_Transmit(hspi,&addrbuf[1],1,0xffff);
            HAL_SPI_Transmit(hspi,&addrbuf[2],1,0xffff);
            HAL_SPI_Transmit(hspi,wbuff,256,0xffff);
            EFLASH_CS_H;
            addr += 256;
            wbuff += 256;
            len -= 256;
        }
        if(len != 0){
            _elfash_busy_wait();
            _elfash_wenable();
            addrbuf[0] = (addr >> 16) & 0x00ff;
            addrbuf[1] = (addr >> 8)  & 0x0000ff;
            addrbuf[2] = (addr) & 0x000000ff;
            EFLASH_CS_L;
            HAL_SPI_Transmit(hspi,&inst,1,0xffff);
            HAL_SPI_Transmit(hspi,&addrbuf[0],1,0xffff);
            HAL_SPI_Transmit(hspi,&addrbuf[1],1,0xffff);
            HAL_SPI_Transmit(hspi,&addrbuf[2],1,0xffff);
            HAL_SPI_Transmit(hspi,wbuff,len,0xffff);
            EFLASH_CS_H;
        }
    }
}